﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Diagnostics;

namespace Prism.Core.Net.Tcp
{
    internal class ProgressableNetworkHelper : NetworkHelper
    {
        public ProgressableNetworkHelper(TcpClient TcpClient)
            : base(TcpClient)
        {
            this.WriteSpeedTracker = new DataTransportSpeedTracker();
            this.ReadSpeedTracker = new DataTransportSpeedTracker();
            this.WriteSpeedTracker.Tick += new EventHandler(WriteSpeedTracker_Tick);
            this.ReadSpeedTracker.Tick += new EventHandler(ReadSpeedTracker_Tick);
            this.WriteSpeedTracker.Start();
            this.ReadSpeedTracker.Start();
        }

        void ReadSpeedTracker_Tick(object sender, EventArgs e)
        {
            this.OnReadDataSpeed(new DataSpeedEventArgs()
            {
                Speed = this.ReadSpeedTracker.NowLength - this.ReadSpeedTracker.PreLength,
                NowDataLength = this.ReadSpeedTracker.NowLength,
                TotalDataLength = this.ReadSpeedTracker.TotalLength
            });
            this.ReadSpeedTracker.PreLength = this.ReadSpeedTracker.NowLength;
        }

        void WriteSpeedTracker_Tick(object sender, EventArgs e)
        {
            this.OnWriteDataSpeed(new DataSpeedEventArgs()
            {
                Speed = this.WriteSpeedTracker.NowLength - this.WriteSpeedTracker.PreLength,
                NowDataLength = this.WriteSpeedTracker.NowLength,
                TotalDataLength = this.WriteSpeedTracker.TotalLength
            });
            this.WriteSpeedTracker.PreLength = this.WriteSpeedTracker.NowLength;
        }

        protected DataTransportSpeedTracker WriteSpeedTracker;
        protected DataTransportSpeedTracker ReadSpeedTracker;

        protected virtual void OnStartWriteDataProgress(object state)
        {
            // 要写入的数据。
            var buffer = state as byte[];
            System.Diagnostics.Debug.Print("要发送的数据的长度：" + buffer.Length.ToString());
            // 要写入的数据的长度。
            var length = buffer.Length;
            // 将长度信息转换为Bytes。
            var lengthHead = BitConverter.GetBytes(length);
            System.Diagnostics.Debug.Print("计算获得的数据的长度：" + length.ToString());
            Debug.Print(buffer.Last().ToString());

            // 发送长度头信息。
            try
            {
                this.NetworkStream.Write(lengthHead, 0, lengthHead.Length);
            }
            catch (IOException ex)
            {
                this.OnWriteDataProgress(new DataProgressEventArgs() { Progress = 0d, IsCompleted = false });
                this.EndWriteCurrent(false, ex);
                return;
            }

            // 获取缓冲总长度。
            this.WriteSpeedTracker.TotalLength = length;

            // 分块操作。
            var offset = 0;

            //开始写数据。
            while (true)
            {
                try
                {
                    if (length - offset >= this.blockSize)
                    {
                        this.NetworkStream.Write(buffer, offset, this.blockSize);
                        offset += this.blockSize;
                        this.WriteSpeedTracker.NowLength = offset;
                    }
                    else if (length - offset < this.blockSize && length != offset)
                    {
                        this.NetworkStream.Write(buffer, offset, length - offset);
                        offset = length;
                        this.WriteSpeedTracker.NowLength = offset;
                    }
                    else break;
                }
                catch (IOException ex)
                {
                    this.OnWriteDataProgress(new DataProgressEventArgs() { Progress = 0d, IsCompleted = false });
                    this.EndWriteCurrent(false, ex);
                    return;
                }
                if (offset % 1024 == 0)
                {
                    var progress = 100 * offset / length;
                    this.OnWriteDataProgress(new DataProgressEventArgs() { Progress = progress, IsCompleted = false });
                }
            }

            this.OnWriteDataProgress(new DataProgressEventArgs() { Progress = 100d, IsCompleted = true });

            // 结束写入。
            this.WriteSpeedTracker = new DataTransportSpeedTracker();
            this.EndWriteCurrent(true, null);

        }

        protected virtual void OnStartReadDataProgress()
        {
            // 初始化长度缓冲。
            var lengthHead = new byte[4];
            try
            {
                this.NetworkStream.Read(lengthHead, 0, lengthHead.Length);
            }
            catch (IOException ex)
            {
                this.EndReadCurrent(null, ex);
                return;
            }
            catch (ObjectDisposedException ex)
            {
                this.EndReadCurrent(null, ex);
                return;
            }

            // 获取长度值。
            var length = BitConverter.ToInt32(lengthHead, 0);
            // 缓冲。
            var buffer = new byte[length];
            // 获取总长度。
            this.ReadSpeedTracker.TotalLength = length;

            // 分块操作。
            var offset = 0;

            // 开始读取数据。
            while (true)
            {
                try
                {
                    if (length - offset >= this.blockSize)
                    {
                        this.NetworkStream.Read(buffer, offset, this.blockSize);
                        offset += this.blockSize;
                        this.ReadSpeedTracker.NowLength = offset;
                    }
                    else if (length - offset < this.blockSize && length != offset)
                    {
                        this.NetworkStream.Read(buffer, offset, length - offset);
                        offset = length;
                        this.ReadSpeedTracker.NowLength = offset;
                    }
                    else break;
                }
                catch (IOException ex)
                {
                    this.OnReadDataProgress(new DataProgressEventArgs() { IsCompleted = false, Progress = 0d });
                    this.EndReadCurrent(null, ex);
                    return;
                }

                if (offset % 1024 == 0)
                {
                    var progress = 100 * offset / length;
                    this.OnReadDataProgress(new DataProgressEventArgs() { IsCompleted = false, Progress = progress });
                }
            }
            // 获取最终值。
            System.Diagnostics.Debug.Print("接收到的头部长度信息：" + length.ToString());
            System.Diagnostics.Debug.Print("实际接收到的数据长度：" + buffer.Length.ToString());
            Debug.Print(buffer.Last().ToString());

            this.OnReadDataProgress(new DataProgressEventArgs() { IsCompleted = true, Progress = 100d });


            // 结束读取。
            this.ReadSpeedTracker = new DataTransportSpeedTracker();
            this.EndReadCurrent(this.OnDeserializeData(buffer), null);

        }

        protected virtual void OnSerializeData(object value)
        {
            using (var ms = new MemoryStream())
            {
                // 创建序列化器。
                var bf = new BinaryFormatter();

                // 序列化对象。
                bf.Serialize(ms, value);

                // 获取缓冲值。
                var buffer = ms.ToArray();

                this.OnStartWriteDataProgress(buffer);
            }
        }

        protected virtual object OnDeserializeData(byte[] buffer)
        {
            object value;
            var bf = new BinaryFormatter();
            using (var ms = new MemoryStream(buffer))
            {
                try
                {
                    value = bf.Deserialize(ms);
                }
                catch (SerializationException ex)
                {
                    value = null;
                    this.EndReadCurrent(null, ex);
                    return value;
                }
            }
            return value;
        }

        protected override void WriteCurrent()
        {
            if (!this.isWriting && this.DataQueue.Count != 0)
            {
                this.isWriting = true;

                object value = this.DataQueue.Dequeue();

                this.OnSerializeData(value);
            }
        }

        protected override void ReadCurrent()
        {

            if ((!this.isReading && this.ReadDataEndCallback != null))
            {
                this.isReading = true;

                this.OnStartReadDataProgress();

            }
        }

        public event EventHandler<DataSpeedEventArgs> WriteDataSpeed;

        protected void OnWriteDataSpeed(DataSpeedEventArgs e)
        {
            if (this.WriteDataSpeed != null) { this.WriteDataSpeed(this, e); }
        }

        public event EventHandler<DataSpeedEventArgs> ReadDataSpeed;

        protected void OnReadDataSpeed(DataSpeedEventArgs e)
        {
            if (this.ReadDataSpeed != null) { this.ReadDataSpeed(this, e); }
        }

        public event EventHandler<DataProgressEventArgs> WriteDataProgress;

        public event EventHandler<DataProgressEventArgs> ReadDataProgress;

        protected void OnWriteDataProgress(DataProgressEventArgs e)
        {
            if (this.WriteDataProgress != null) { this.WriteDataProgress(this, e); }
        }

        protected void OnReadDataProgress(DataProgressEventArgs e)
        {
            if (this.ReadDataProgress != null) { this.ReadDataProgress(this, e); }
        }

        protected int blockSize = 0x001000; // 4KB

        public int BlockSize
        {
            get { return blockSize; }
            set { blockSize = value; }
        }
    }
}
